package com.dxb.test.algorithm;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.Data;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * ClassName：algorithm.SlidingTimeWindow <br>
 * Description：滑动窗口 <br>
 *
 * @author 戴晓波 <br>
 * Date 2022/2/10/010 14:42 <br>
 * @version v1.0 <br>
 */
@Data
public class SlidingTimeWindow {
    /**
     * 窗口大小（单位秒）
     */
    private int width;
    /**
     * 窗口最大容量
     */
    private int limit;
    private LoadingCache<Long, AtomicLong> counter;

    public SlidingTimeWindow(int width, int limit) {
        this.width = width;
        this.limit = limit;
        counter = CacheBuilder.newBuilder()
                .expireAfterWrite(width, TimeUnit.SECONDS)
                // 设置初始容量
                .initialCapacity(width)
                //缓存的并发级别
                .concurrencyLevel(Runtime.getRuntime().availableProcessors())
                .build(new CacheLoader<Long, AtomicLong>() {
                    @Override
                    public AtomicLong load(Long seconds) throws Exception {
                        return new AtomicLong(0);
                    }
                });
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        SlidingTimeWindow window = new SlidingTimeWindow(10, 10);
        while (true) {
            long now = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
            System.out.println(now);
            long total = 0;
            for (int i = 0; i < window.getWidth(); i++) {
                total += window.getCounter().get(now - i).get();
            }
            if (total >= window.getLimit()) {
                System.out.println("限流了,total=" + total);
            } else {
                //每秒发送随机数量的请求
                int reqs = (int) (Math.random() * 5) + 1;
                window.getCounter().get(now).addAndGet(reqs);
            }
            Thread.sleep(1000);
        }
    }
}
